package com.kakame.codenews.base.web.aop;

import java.util.Arrays;

import javax.annotation.Resource;

import org.apache.commons.lang3.StringUtils;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;

import com.kakame.codenews.base.util.JsonUtil;
import com.kakame.codenews.base.util.RedisUtil;
import com.kakame.codenews.base.util.SystemUtil;
import com.kakame.codenews.base.web.annotation.CacheOperate;
import com.kakame.codenews.base.web.enumeration.CacheOperateType;
import com.kakame.codenews.base.web.exception.NonCacheException;

/**
 * 缓存操作
 * 
 * @author 何家明 2018年7月22日 上午1:01:34
 */
@Aspect // 该注解标示该类为切面类
@Component // 注入依赖
public class CacheAspect {
	
    private Logger logger = LoggerFactory.getLogger(this.getClass().getPackage().getName());
    
	@Resource
	private RedisUtil redisUtil;

	@Around("within(com.kakame.codenews..*) && @annotation(cacheOperate)")
	public Object invokeCache(ProceedingJoinPoint pjp, CacheOperate cacheOperate) {

	    Object[] args = pjp.getArgs();
	    
		Signature signature = pjp.getSignature();
		String declaringTypeName = signature.getDeclaringTypeName();
		String methodName = signature.getName();
		
		String cacheName = cacheOperate.cacheName();
		if(StringUtils.isBlank(cacheName)) {
		    // 默认以类全名+方法名生成缓存名
			cacheName = declaringTypeName + "." + methodName;
		}
		if(!SystemUtil.isNull(args)) {
		    cacheName += Arrays.toString(args);
		}
		
		// 1、先获取用户的操作类型
		CacheOperateType operateType = cacheOperate.operateType();
        switch (operateType) {
        case GET:
            String redisVal = redisUtil.get(cacheName);
            if(StringUtils.isNotBlank(redisVal)) {  // 已经有此缓存了，就从缓存里面取值
                logger.info("存在缓存，开始从缓存中取值...");
                Class<?> returnType = cacheOperate.returnType();
                Object parse = null;
                if(returnType.getClass().equals(java.util.List.class)) {
                    parse = JsonUtil.toObject(redisVal);
                } else {
                    parse = JsonUtil.toObject(redisVal, returnType);
                }
                logger.info("缓存取值结束...");
                return parse;
            } else {  // 没有缓存，就从数据库里面取
                logger.info("无缓存，开始执行方法...");
                Object result = null;
                try {
                    result = pjp.proceed();
                } catch (Throwable e) {
                    e.printStackTrace();
                }
                if(result != null) {
                    String jsonString = JsonUtil.toJson(result);
                    logger.info("开始向缓存中写入数据...");
                    redisUtil.set(cacheName, jsonString);
                }
                logger.info("执行方法结束...");
                return result;
            }
        case SET_AND_COVER:
            if(!SystemUtil.isNull(args) && !SystemUtil.isBaseType(args)) {
                throw new NonCacheException("要进行缓存的方法，参数必须为空，或者8大基本数据类型，或者是字符串");
            }
            Object result = null;
            try {
                result = pjp.proceed();
            } catch (Throwable e) {
                e.printStackTrace();
            }
            if(result != null) {
                String jsonString = JsonUtil.toJson(result);
                redisUtil.set(cacheName, jsonString);
            }
            return result;
        case DELETE:
            Object resultD = null;
            try {
                resultD = pjp.proceed();
            } catch (Throwable e) {
                e.printStackTrace();
            }
            if(resultD != null) {
                
                String[] deleteCaches = cacheOperate.deleteCaches();
                boolean deleteWithPre = cacheOperate.deleteWithPre();
                if(deleteWithPre) {
                    for (String string : deleteCaches) {
                        redisUtil.deleteByPre(declaringTypeName + "." + string);
                    }
                } else {
                    for (String string : deleteCaches) {
                        redisUtil.delete(declaringTypeName + "." + string);
                    }
                }
            }
            return resultD;
        case DELETE_ALL:
            redisUtil.flushDb();
            break;
        default:
            break;
        }
		return null;
	}
}
